home *** CD-ROM | disk | FTP | other *** search
/ Programming Windows 95 with MFC / Programming Windows 95 with MFC (Microsoft Programming Series)(097-0001465)(1996).iso / CODE / Chap03 / VisualKB / VisualKB.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-05  |  10.0 KB  |  381 lines

  1. //***********************************************************************
  2. //
  3. //  VisualKB.cpp
  4. //
  5. //***********************************************************************
  6.  
  7. #include <afxwin.h>
  8. #include "Resource.h"
  9. #include "VisualKB.h"
  10.  
  11. CMyApp myApp;
  12.  
  13. /////////////////////////////////////////////////////////////////////////
  14. // CMyApp member functions
  15.  
  16. BOOL CMyApp::InitInstance ()
  17. {
  18.     m_pMainWnd = new CMainWindow;
  19.     m_pMainWnd->ShowWindow (m_nCmdShow);
  20.     m_pMainWnd->UpdateWindow ();
  21.     return TRUE;
  22. }
  23.  
  24. /////////////////////////////////////////////////////////////////////////
  25. // CMainWindow message map and member functions
  26.  
  27. BEGIN_MESSAGE_MAP (CMainWindow, CWnd)
  28.     ON_WM_CREATE ()
  29.     ON_WM_PAINT ()
  30.     ON_WM_SETFOCUS ()
  31.     ON_WM_KILLFOCUS ()
  32.     ON_WM_SETCURSOR ()
  33.     ON_WM_LBUTTONDOWN ()
  34.     ON_WM_KEYDOWN ()
  35.     ON_WM_KEYUP ()
  36.     ON_WM_SYSKEYDOWN ()
  37.     ON_WM_SYSKEYUP ()
  38.     ON_WM_CHAR ()
  39.     ON_WM_SYSCHAR ()
  40. END_MESSAGE_MAP ()
  41.  
  42. CMainWindow::CMainWindow ()
  43. {
  44.     m_nTextPos = 0;
  45.     m_nMsgPos = 0;
  46.  
  47.     m_hCursorArrow = myApp.LoadStandardCursor (IDC_ARROW);
  48.     m_hCursorIBeam = myApp.LoadStandardCursor (IDC_IBEAM);
  49.  
  50.     CString strWndClass = AfxRegisterWndClass (
  51.         0,
  52.         NULL,
  53.         (HBRUSH) (COLOR_3DFACE + 1),
  54.         myApp.LoadIcon (IDI_APPICON)
  55.     );
  56.  
  57.     CreateEx (0, strWndClass, "Visual Keyboard",
  58.         WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
  59.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  60.         NULL, NULL);
  61. }
  62.  
  63. int CMainWindow::OnCreate (LPCREATESTRUCT lpcs)
  64. {
  65.     if (CWnd::OnCreate (lpcs) == -1)
  66.         return -1;
  67.     
  68.     CClientDC dc (this);
  69.  
  70.     TEXTMETRIC tm;
  71.     dc.GetTextMetrics (&tm);
  72.     m_cxChar = tm.tmAveCharWidth;
  73.     m_cyChar = tm.tmHeight;
  74.     m_cyLine = tm.tmHeight + tm.tmExternalLeading;
  75.  
  76.     m_rcTextBoxBorder.SetRect (16, 16, (m_cxChar * 64) + 16,
  77.         ((m_cyChar * 3) / 2) + 16);
  78.  
  79.     m_rcTextBox = m_rcTextBoxBorder;
  80.     m_rcTextBox.InflateRect (-2, -2);
  81.     
  82.     m_rcMsgBoxBorder.SetRect (16, (m_cyChar * 4) + 16,
  83.         (m_cxChar * 64) + 16, (m_cyLine * MAX_STRINGS) +
  84.         (m_cyChar * 6) + 16);
  85.  
  86.     m_rcScroll.SetRect (m_cxChar + 16, (m_cyChar * 6) + 16,
  87.         (m_cxChar * 63) + 16, (m_cyLine * MAX_STRINGS) +
  88.         (m_cyChar * 5) + 16);
  89.  
  90.     m_ptTextOrigin.x = m_cxChar + 16;
  91.     m_ptTextOrigin.y = (m_cyChar / 4) + 16;
  92.     m_ptCaretPos = m_ptTextOrigin;
  93.     m_nTextLimit = (m_cxChar * 63) + 16;
  94.  
  95.     m_ptHeaderOrigin.x = m_cxChar + 16;
  96.     m_ptHeaderOrigin.y = (m_cyChar * 3) + 16;
  97.  
  98.     m_ptUpperMsgOrigin.x = m_cxChar + 16;
  99.     m_ptUpperMsgOrigin.y = (m_cyChar * 5) + 16;
  100.  
  101.     m_ptLowerMsgOrigin.x = m_cxChar + 16;
  102.     m_ptLowerMsgOrigin.y = (m_cyChar * 5) +
  103.         (m_cyLine * (MAX_STRINGS - 1)) + 16;
  104.  
  105.     m_nTabStops[0] = (m_cxChar * 24) + 16;
  106.     m_nTabStops[1] = (m_cxChar * 30) + 16;
  107.     m_nTabStops[2] = (m_cxChar * 36) + 16;
  108.     m_nTabStops[3] = (m_cxChar * 42) + 16;
  109.     m_nTabStops[4] = (m_cxChar * 46) + 16;
  110.     m_nTabStops[5] = (m_cxChar * 50) + 16;
  111.     m_nTabStops[6] = (m_cxChar * 54) + 16;
  112.  
  113.     CRect rect (0, 0, m_rcMsgBoxBorder.right + 16,
  114.         m_rcMsgBoxBorder.bottom + 16);
  115.     CalcWindowRect (&rect);
  116.  
  117.     SetWindowPos (NULL, 0, 0, rect.Width (), rect.Height (),
  118.         SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW);
  119.     return 0;
  120. }
  121.  
  122. void CMainWindow::PostNcDestroy ()
  123. {
  124.     delete this;
  125. }
  126.  
  127. void CMainWindow::OnPaint ()
  128. {
  129.     CPaintDC dc (this);
  130.  
  131.     dc.DrawEdge (m_rcTextBoxBorder, EDGE_SUNKEN, BF_RECT);
  132.     dc.DrawEdge (m_rcMsgBoxBorder, EDGE_SUNKEN, BF_RECT);
  133.  
  134.     DrawInputText (&dc);
  135.     DrawMessageHeader (&dc);
  136.     DrawMessages (&dc);
  137. }
  138.  
  139. void CMainWindow::OnSetFocus (CWnd* pWnd)
  140. {
  141.     CreateSolidCaret (max (2, ::GetSystemMetrics (SM_CXBORDER)),
  142.         m_cyChar);
  143.     SetCaretPos (m_ptCaretPos);
  144.     ShowCaret ();
  145. }
  146.  
  147. void CMainWindow::OnKillFocus (CWnd* pWnd)
  148. {
  149.     HideCaret ();
  150.     m_ptCaretPos = GetCaretPos ();
  151.     ::DestroyCaret ();
  152. }
  153.  
  154. BOOL CMainWindow::OnSetCursor (CWnd* pWnd, UINT nHitTest, UINT message)
  155. {
  156.     if (nHitTest == HTCLIENT) {
  157.         DWORD dwPos = ::GetMessagePos ();
  158.         CPoint point (LOWORD (dwPos), HIWORD (dwPos));
  159.         ScreenToClient (&point);
  160.         ::SetCursor (m_rcTextBox.PtInRect (point) ?
  161.             m_hCursorIBeam : m_hCursorArrow);
  162.         return TRUE;
  163.     }
  164.     return CWnd::OnSetCursor (pWnd, nHitTest, message);
  165. }
  166.  
  167. void CMainWindow::OnLButtonDown (UINT nFlags, CPoint point)
  168. {
  169.     if (m_rcTextBox.PtInRect (point)) {
  170.         m_nTextPos = GetNearestPos (point);
  171.         PositionCaret ();
  172.     }
  173. }
  174.  
  175. void CMainWindow::OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags)
  176. {
  177.     ShowMessage ("WM_KEYDOWN", nChar, nRepCnt, nFlags);
  178.  
  179.     switch (nChar) {
  180.  
  181.     case VK_LEFT:
  182.         if (m_nTextPos != 0) {
  183.             m_nTextPos--;
  184.             PositionCaret ();
  185.         }
  186.         break;
  187.  
  188.     case VK_RIGHT:
  189.         if (m_nTextPos != m_strInputText.GetLength ()) {
  190.             m_nTextPos++;
  191.             PositionCaret ();
  192.         }
  193.         break;
  194.  
  195.     case VK_HOME:
  196.         m_nTextPos = 0;
  197.         PositionCaret ();
  198.         break;
  199.  
  200.     case VK_END:
  201.         m_nTextPos = m_strInputText.GetLength ();
  202.         PositionCaret ();
  203.         break;
  204.     }
  205. }
  206.  
  207. void CMainWindow::OnChar (UINT nChar, UINT nRepCnt, UINT nFlags)
  208. {
  209.     ShowMessage ("WM_CHAR", nChar, nRepCnt, nFlags);
  210.  
  211.     CClientDC dc (this);
  212.  
  213.     switch (nChar) {
  214.  
  215.     case VK_ESCAPE:
  216.     case VK_RETURN:
  217.         m_strInputText.Empty ();
  218.         m_nTextPos = 0;
  219.         break;
  220.  
  221.     case VK_BACK:
  222.         if (m_nTextPos != 0) {
  223.             m_strInputText = m_strInputText.Left (m_nTextPos - 1) +
  224.                 m_strInputText.Right (m_strInputText.GetLength () -
  225.                 m_nTextPos);
  226.             m_nTextPos--;
  227.         }
  228.         break;
  229.  
  230.     default:
  231.         if ((nChar >= 0) && (nChar <= 31))
  232.             return;
  233.  
  234.         if (m_nTextPos == m_strInputText.GetLength ()) {
  235.             m_strInputText += nChar;
  236.             m_nTextPos++;
  237.         }
  238.         else
  239.             m_strInputText.SetAt (m_nTextPos++, nChar);
  240.  
  241.         CSize size = dc.GetTextExtent (m_strInputText,
  242.             m_strInputText.GetLength ());
  243.  
  244.         if ((m_ptTextOrigin.x + size.cx) > m_nTextLimit) {
  245.             m_strInputText = nChar;
  246.             m_nTextPos = 1;
  247.         }
  248.         break;
  249.     }
  250.  
  251.     HideCaret ();
  252.     DrawInputText (&dc);
  253.     PositionCaret (&dc);
  254.     ShowCaret ();
  255. }
  256.  
  257. void CMainWindow::OnKeyUp (UINT nChar, UINT nRepCnt, UINT nFlags)
  258. {
  259.     ShowMessage ("WM_KEYUP", nChar, nRepCnt, nFlags);
  260.     CWnd::OnKeyUp (nChar, nRepCnt, nFlags);
  261. }
  262.  
  263. void CMainWindow::OnSysKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags)
  264. {
  265.     ShowMessage ("WM_SYSKEYDOWN", nChar, nRepCnt, nFlags);
  266.     CWnd::OnSysKeyDown (nChar, nRepCnt, nFlags);
  267. }
  268.  
  269. void CMainWindow::OnSysChar (UINT nChar, UINT nRepCnt, UINT nFlags)
  270. {
  271.     ShowMessage ("WM_SYSCHAR", nChar, nRepCnt, nFlags);
  272.     CWnd::OnSysChar (nChar, nRepCnt, nFlags);
  273. }
  274.  
  275. void CMainWindow::OnSysKeyUp (UINT nChar, UINT nRepCnt, UINT nFlags)
  276. {
  277.     ShowMessage ("WM_SYSKEYUP", nChar, nRepCnt, nFlags);
  278.     CWnd::OnSysKeyUp (nChar, nRepCnt, nFlags);
  279. }
  280.  
  281. void CMainWindow::PositionCaret (CDC* pDC)
  282. {
  283.     BOOL bRelease = FALSE;
  284.  
  285.     if (pDC == NULL) {
  286.         pDC = GetDC ();
  287.         bRelease = TRUE;
  288.     }
  289.  
  290.     CPoint point = m_ptTextOrigin;
  291.     CString string = m_strInputText.Left (m_nTextPos);
  292.     point.x += (pDC->GetTextExtent (string, string.GetLength ())).cx;
  293.     SetCaretPos (point);
  294.  
  295.     if (bRelease)
  296.         ReleaseDC (pDC);
  297. }
  298.  
  299. int CMainWindow::GetNearestPos (CPoint point)
  300. {
  301.     if (point.x <= m_ptTextOrigin.x)
  302.         return 0;
  303.  
  304.     CClientDC dc (this);
  305.     int nLen = m_strInputText.GetLength ();
  306.     if (point.x >= (m_ptTextOrigin.x +
  307.         (dc.GetTextExtent (m_strInputText, nLen)).cx))
  308.         return nLen;
  309.  
  310.     int i = 0;
  311.     int nPrevChar = m_ptTextOrigin.x;
  312.     int nNextChar = m_ptTextOrigin.x;
  313.  
  314.     while (nNextChar < point.x) {
  315.         i++;
  316.         nPrevChar = nNextChar;      
  317.         nNextChar = m_ptTextOrigin.x +
  318.             (dc.GetTextExtent (m_strInputText.Left (i), i)).cx;
  319.     }
  320.     return ((point.x - nPrevChar) < (nNextChar - point.x)) ? i - 1: i;
  321. }
  322.  
  323. void CMainWindow::DrawInputText (CDC* pDC)
  324. {
  325.     pDC->ExtTextOut (m_ptTextOrigin.x, m_ptTextOrigin.y,
  326.         ETO_OPAQUE, m_rcTextBox, m_strInputText, NULL);
  327. }
  328.  
  329. void CMainWindow::ShowMessage (LPCTSTR pszMessage, UINT nChar,
  330.     UINT nRepCnt, UINT nFlags)
  331. {
  332.     CString string;
  333.     string.Format ("%s\t %u\t  %u\t  %u\t  %u\t  %u\t  %u\t   %u",
  334.         pszMessage, nChar, nRepCnt, nFlags & 0xFF,
  335.         (nFlags >> 8) & 0x01,
  336.         (nFlags >> 13) & 0x01,
  337.         (nFlags >> 14) & 0x01,
  338.         (nFlags >> 15) & 0x01);
  339.  
  340.     ScrollWindow (0, -m_cyLine, &m_rcScroll);
  341.     ValidateRect (m_rcScroll);
  342.  
  343.     CClientDC dc (this);
  344.     dc.SetBkColor ((COLORREF) ::GetSysColor (COLOR_3DFACE));
  345.  
  346.     m_strMessages[m_nMsgPos] = string;
  347.     dc.TabbedTextOut (m_ptLowerMsgOrigin.x, m_ptLowerMsgOrigin.y,
  348.         m_strMessages[m_nMsgPos], m_strMessages[m_nMsgPos].GetLength (),
  349.         sizeof (m_nTabStops), m_nTabStops, m_ptLowerMsgOrigin.x);
  350.  
  351.     if (++m_nMsgPos == MAX_STRINGS)
  352.         m_nMsgPos = 0;  
  353. }
  354.  
  355. void CMainWindow::DrawMessageHeader (CDC* pDC)
  356. {
  357.     static CString string =
  358.         "Message\tChar\tRep\tScan\tExt\tCon\tPrv\tTran";
  359.  
  360.     pDC->SetBkColor ((COLORREF) ::GetSysColor (COLOR_3DFACE));
  361.     pDC->TabbedTextOut (m_ptHeaderOrigin.x, m_ptHeaderOrigin.y,
  362.         string, string.GetLength (), sizeof (m_nTabStops), m_nTabStops,
  363.         m_ptHeaderOrigin.x);
  364. }
  365.  
  366. void CMainWindow::DrawMessages (CDC* pDC)
  367. {
  368.     int nPos = m_nMsgPos;
  369.     pDC->SetBkColor ((COLORREF) ::GetSysColor (COLOR_3DFACE));
  370.  
  371.     for (int i=0; i<MAX_STRINGS; i++) {
  372.         pDC->TabbedTextOut (m_ptUpperMsgOrigin.x,
  373.             m_ptUpperMsgOrigin.y + (m_cyLine * i),
  374.             m_strMessages[nPos], m_strMessages[nPos].GetLength (),
  375.             sizeof (m_nTabStops), m_nTabStops, m_ptUpperMsgOrigin.x);
  376.  
  377.         if (++nPos == MAX_STRINGS)
  378.             nPos = 0;    
  379.     }
  380. }
  381.